package org.monster.context.core.processor;

import org.dom4j.DocumentException;
import org.monster.context.core.ApplicationClassLoaderImpl;
import org.monster.context.core.FilterConfigCache;
import org.monster.context.core.ServletConfigCache;
import org.monster.context.core.filter.ApplicationFilterChain;
import org.monster.context.core.parameter.HttpResponse;
import org.monster.context.core.request.HttpRequest;
import org.monster.context.reader.tag.FilterTag;
import org.monster.context.reader.tag.ServletTag;
import org.monster.context.servlet.ServletContainer;
import org.monster.context.servlet.ServletContextConfig;
import org.monster.context.servlet.ServletExecutor;
import org.monster.context.util.URIUtils;

import javax.servlet.Filter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * 处理服务者
 *
 * @author Monster
 */
public class ProcessServlet implements Process {

    /**
     * 日志器
     */
    private static final Logger logger = Logger.getLogger(ProcessServlet.class.getName());
    /**
     * 过滤器配置键值
     */
    private final FilterConfigCache filterConfigCache = FilterConfigCache.getFilterConfigCache();
    /**
     * 服务者配置缓存
     */
    private final ServletConfigCache servletConfigCache = ServletConfigCache.getServletConfigCache();
    /**
     * 服务者容器
     */
    private final ServletContainer container = ServletContainer.getContainer();
    /**
     * 服务者上下文配置
     */
    private ServletContextConfig config;
    /**
     * 应用类加载器
     */
    private ApplicationClassLoaderImpl loader;

    /**
     * 构造方法
     */
    public ProcessServlet() {
        config = new ServletContextConfig();
        loader = new ApplicationClassLoaderImpl();
    }

    /**
     * 过滤处理Servlet请求
     *
     * @param request  请求
     * @param response 响应
     */
    public void processFilter(HttpRequest request, HttpResponse response) {
        String requestURI = request.getRequestURI(request.getURI());
        String appName = URIUtils.startWithURI(requestURI);
        List<FilterTag> tags = filterConfigCache.getTag(appName);
        if (tags != null) {
            List<Filter> filters = new ArrayList<>();
            String endsURI = URIUtils.allEndsWithURI(requestURI);
            for (FilterTag filterTag : tags) {
                if (filterTag.getMappingFilterUrlPattern().equals(endsURI)) {
                    String className = filterTag.getFilterClass();
                    Filter filter = filterConfigCache.getFilter(appName + "_"
                            + className);
                    filters.add(filter);
                }
            }
            if (filters.size() > 0) {
                try {
                    ApplicationFilterChain applicChain = new ApplicationFilterChain(
                            filters);
                    applicChain.doFilter(request, response);
                } catch (IOException | ServletException ex) {
                    logger.log(Level.SEVERE, null, ex);
                }
            }
        }
    }

    /**
     * 处理
     *
     * @param request  请求
     * @param response 响应
     */
    @Override
    public boolean process(HttpRequest request, HttpResponse response) {
        processFilter(request, response);
        // 请求的URI
        String requestURI = request.getRequestURI();
        String appName = URIUtils.startWithURI(requestURI);
        // 获取请求的项目的classes目录下的加载（在classes下还有package包文件夹）
        loader.getWebClassLoader(appName);
        HttpServlet servlet = null;
        String endsURI = URIUtils.allEndsWithURI(requestURI);
        List<ServletTag> tags = servletConfigCache.getTags(appName);
        if (tags != null) {
            for (ServletTag servletTag : tags) {
                if (servletTag.getMappingUrlPattern().equals(endsURI)) {
                    String className = servletTag.getServletClass();
                    servlet = container
                            .getServlet(appName + "_" + className);
                }
            }
        }
        String classpath = null;
        if (servlet == null) {
            try {
                classpath = config.getServletConfig(request);
            } catch (DocumentException ex) {
                logger.log(Level.SEVERE, null, ex);
            }
            servlet = container.getServlet(appName + "_" + classpath);
        }
        ServletExecutor executor = new ServletExecutor(servlet);
        if (servlet != null) {
            executor.service(request, response, servlet);
        } else {
            if (classpath != null) {
                try {
                    Class<?> clazz = loader.loadClass(classpath);
                    servlet = executor.service(request, response, clazz);
                    container.addServlet(appName + "_" + classpath, servlet);
                } catch (ClassNotFoundException ex) {
                    logger.log(Level.SEVERE, null, ex);
                }
            }
        }
        return servlet != null;
    }

}
